package com.doubledragon.tiny.aop.autoProxyCreator;

import com.doubledragon.tiny.aop.daynamicProxy.AdvisedSupport;
import com.doubledragon.tiny.aop.daynamicProxy.JdkDynamicProxy;
import com.doubledragon.tiny.aop.daynamicProxy.TargetSource;
import com.doubledragon.tiny.aop.pointcutAdvisor.AspectJExpressionPointcut;
import com.doubledragon.tiny.aop.pointcutAdvisor.AspectJExpressionPointcutAdvisor;
import com.doubledragon.tiny.ioc.factory.AbstractBeanFactory;
import com.doubledragon.tiny.ioc.factory.BeanFactory;
import org.aopalliance.intercept.MethodInterceptor;

import java.util.List;

/**
 * Created by dragon
 *
 * 作为一个Bean处理器（实现了BeanPostProcessor接口），在bean初始化之后, 利用pointcutAdvisor判断
 * 当前bean是否符合某一个pointcut表达式对应的增强器，如果符合，则创建aop代理对象,并返回。
 *
 * 在spring源码中，如果配置有<aop:aspectj-autoproxy>，则直接new一个AnnotationAwareAspectJAutoProxyCreator放入容器。
 */
public class AspectjAtuoProxyCreator implements BeanPostProcessor, BeanFactoryAware{

    private AbstractBeanFactory beanFactory;

    @Override
    public void setBeanFactory(BeanFactory beanFactory) {
        this.beanFactory = (AbstractBeanFactory)beanFactory;
    }

    //bean前置处理器
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws Exception {
        return bean;
    }

    //bean后置处理器
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws Exception {
        //如果当前bean是MethodInterceptor子类，则不需要生成代理
        if(bean instanceof MethodInterceptor){
            return bean;
        }
        //如果当前bean是AspectJExpressionPointcutAdvisor子类，则不需要生成代理
        if(bean instanceof AspectJExpressionPointcutAdvisor){
            return bean;
        }
        //从容器中找出所有pointcut表达式解析增强器
        List pointcutAdvisors = beanFactory.getBeanByType(AspectJExpressionPointcutAdvisor.class);
        for (Object object : pointcutAdvisors) {
            AspectJExpressionPointcutAdvisor pointcutAdvisor = (AspectJExpressionPointcutAdvisor) object;
            //如果当前bean符合当前的pointcut表达式解析，则用代理方式对里面的方法进行增强操作, 并返回代理类
            //因此，当两个切面对同一个切点进行增强时，会在原来的代理类的基础上，再生成代理类。
            if(pointcutAdvisor.getPointcut().getClassMatcher().matches(bean.getClass())){
                //构造AdvisedSupport
                AdvisedSupport advisedSupport = new AdvisedSupport();
                advisedSupport.setTargetSource(new TargetSource(bean, bean.getClass()));
                advisedSupport.setMethodMatcher(pointcutAdvisor.getPointcut().getMethodMatcher());
                advisedSupport.setMethodInterceptor((MethodInterceptor) pointcutAdvisor.getAdvice());
                //获取代理类
                return new JdkDynamicProxy(advisedSupport).getProxy();
            }
        }
        return bean;
    }
}
